﻿using System;
using System.Collections.Generic;
using System.Linq;
using Crossroad.Core.Data;
using Crossroad.Core.Exceptions;
using Crossroad.Core.Models;
using Crossroad.System.Admin.Model;
using Crossroad.Utils.Extensions;
using SqlSugar;

namespace Crossroad.System.Admin.Service.Impl
{
    /// <summary>
    /// 系统菜单
    /// </summary>
    public class MenuService: Access<Menu>, IMenuService
    {
        private readonly OptionService optionService;
        private readonly RoleJoinMenuOptionService rmoService;

        public MenuService(
            IOptionService optionServiceIpt,
            IRoleJoinMenuOptionService rmoServiceIpt
        )
        {
            optionService = optionServiceIpt as OptionService;
            rmoService = rmoServiceIpt as RoleJoinMenuOptionService;
        }


        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="method"></param>
        /// <param name="loadRelevantData">是否加载关联数据</param>
        public Pagination<Menu> GetPaging(
            int pageIndex,
            int pageSize,
            Action<ISugarQueryable<Menu>> method,
			bool loadRelevantData = true
        )
        {
            var query =  db.Queryable<Menu>();
            method(query);
            var totalCount = 0;
            var page = new Pagination<Menu>
            {
                PageIndex = pageIndex,
                PageSize = pageSize,
            };
            page.Records = query.ToPageList(page.PageIndex, page.PageSize, ref totalCount);
            page.TotalCount = totalCount;
			if(loadRelevantData)
                Load(page.Records);

            return page;
        }

        /// <summary>
        /// 查询列表
        /// </summary>
        /// <param name="method"></param>
        /// <param name="loadRelevantData">是否加载关联数据</param>
        /// <returns></returns>
        public  List<Menu> GetList(
            Action<ISugarQueryable<Menu>> method,
			bool loadRelevantData = true
        )
        {
            var query =  db.Queryable<Menu>();
            method(query);
            var list = query.ToList();
			if(loadRelevantData)
				Load(list);

            return list;
        }

        /// <summary>
        /// 查询角色下的菜单
        /// </summary>
        /// <param name="roleId"></param>
        /// <param name="loadRelevantData"></param>
        /// <returns></returns>
        public  List<Menu> GetList(
            Action<ISugarQueryable<Menu, RoleJoinMenuOption>> method,
			bool loadRelevantData = true
        )
        {
            var query =  db.Queryable<Menu, RoleJoinMenuOption>((a,b) => new object[]
            {
                JoinType.Left, a.id == b.menuId
            });
            method(query);
            var list = query.ToList();
			if(loadRelevantData)
				Load(list);

            return list;
        }

        /// <summary>
        /// 根据角色获取菜单id列表 
        /// </summary>
        /// <param name="roleId"></param>
        /// <param name="typeId"></param>
        /// <returns></returns>
        public List<int> GetIdListByRole(
            int roleId,
            int? typeId
        ) 
        { 
            var query =  db.Queryable<Menu, RoleJoinMenuOption>((a,b) => new object[]
            {
                JoinType.Left, a.id == b.menuId
            });
            query.Where((a, b) => b.roleId == roleId);
            if (typeId.NotNull())
                query.Where((a, b) => a.typeId == typeId);
            var list = query
                 .GroupBy((a, b) => a.id)
                 .Select(a => a.id)
                 .ToList();

            return list;
        }

        /// <summary>
        /// 查询列表 角色关联菜单时使用
        /// </summary>
        /// <param name="method"></param>
        /// <param name="roleId"></param>
        /// <returns></returns>
        public List<Menu> GetList(
            Action<ISugarQueryable<Menu>> method,
            int? roleId
        )
        {
            var query =  db.Queryable<Menu>();
            method(query);
            var list = query.ToList();
            Load(list, roleId);

            return list;
        }

        /// <summary>
        /// 字典数据返回
        /// </summary>
        /// <param name="method"></param>
        /// <returns></returns>
        public object GetDicList(
            Action<ISugarQueryable<Menu>> method
		)
        {
            var query = db.Queryable<Menu>();
            method(query);

            return query.Select(m => new DicDom { label = m.label, value = m.id.ToString() }).ToArray();
        }

        /// <summary>
        /// 查询详情
        /// </summary>
        /// <param name="id"></param>
        /// <param name="loadRelevantData">是否加载关联数据</param>
        /// <returns></returns>
        public Menu GetEntity(dynamic id, bool loadRelevantData = true)
        {
            var model = db.Queryable<Menu>().InSingle(id);
            if (loadRelevantData)
                Load(model);

            return model;
        }

        /// <summary>
        /// 查询详情
        /// </summary>
        /// <param name="method"></param>
        /// <param name="loadRelevantData">是否加载关联数据</param>
        /// <returns></returns>
        public Menu GetEntity(
            Action<ISugarQueryable<Menu>> method,
			bool loadRelevantData = true
		)
        {
            var query = db.Queryable<Menu>();
            method(query);
            var model = query.First();
            if (loadRelevantData)
                Load(model);

            return model;
        }

        /// <summary>
        /// 根据id列表查询maps
        /// </summary>
        /// <param name="idList"></param>
        /// <returns></returns>
        public Dictionary<int, Menu> GetMaps(List<int> idList)
        {
            var maps = new Dictionary<int, Menu>();
            if (idList.Count < 1)
                return maps;

            var list = db.Queryable<Menu>()
                .In(f => f.id, idList.Distinct().ToArray())
                .ToList();

            list.ForEach(m =>
            {
                maps.Add(m.id, m);
            });

            return maps;
        }

        /// <summary>
        /// 新增返回详情
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public Menu CreateAt(Menu model)
        {
            model.layerList = null;
            model.layerNum = null;
            model.createTime = DateTime.Now.ToTimeStamp();
            try
            {
                BeginTran();
                model = db.Insertable(model).ExecuteReturnEntity();

                if (model.parentId.NotContent())
                {
                    model.layerList = $",{model.id},";
                    model.layerNum = 1;
                }
                else
                {
                    var parent = GetEntity(model.parentId, false);
                    model.layerList = $"{parent.layerList}{model.id},";
                    model.layerNum = model.layerList.DelLastComma().AppearaCount(',');
                }
                var rows = db.Updateable(model).UpdateColumns(f => new { f.layerList, f.layerNum }).ExecuteCommand();
                if (rows < 1)
                    throw new LogicException("修改layer id列表及深度失败！");

                CommitTran();
            }
            catch
            {
                RollbackTran();
            }

            return GetEntity(model.id);
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="model"></param>
		public Menu UpdateAt(Menu model) 
		{
            model.updateTime = DateTime.Now.ToTimeStamp();
            var rows = db.Updateable(model).IgnoreColumns(true).ExecuteCommand();
            if (rows < 1)
                throw new LogicException("菜单修改失败！");

            return GetEntity(model.id);
		}

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="source"></param>
        public void DeleteAt(Menu source)
        {
            BeginTran();
            try
            {
                var idList  = db.Queryable<Menu>().Where(a => SqlFunc.Contains(a.layerList, $",{source.id},")).Select(a => a.id).ToArray();
                var rows = db.Deleteable<Menu>().In(idList).ExecuteCommand();
                if (rows < 1)
                    throw new LogicException("菜单删除失败！");
                db.Deleteable<RoleJoinMenuOption>().In(a => a.menuId, idList).ExecuteCommand();
                CommitTran();
            }
            catch (Exception e)
            {
                RollbackTran();
                throw e;
            }
        }


        #region 加载关联数据

        public void Load(List<Menu> list)
        {
            Load(list, null);
        }

        public void Load(List<Menu> list, int? roleId)
        {
            if (list.IsNullOfEmpty())
                return;

            var parentIdList = new List<int>();
            list.ForEach(m =>
            {
                if(!m.parentId.NotContent())
                    parentIdList.Add(m.parentId.Value); 
            });
                
            var parentMaps = GetMaps(parentIdList);
            var options = optionService.GetList(queryable => queryable.OrderBy(a => a.sort), false);

            List<RoleJoinMenuOption> rmoList = null;
            if (!roleId.NotContent())
            {
                rmoList = rmoService.GetList(queryable =>
                {
                    if(roleId.NotNull())
                        queryable.Where(a => a.roleId == roleId);
                });
            }

            list.ForEach(m =>
            {
                if (parentMaps.ContainsKey(m.parentId.Value))
                    m.parentLabel = parentMaps[m.parentId.Value].label;
                if (!m.optionIds.IsNullOfEmpty() && !options.IsNullOfEmpty())
                {
                    var arr = m.optionIds.SplitStrList();
                    m.options = options.Where(f => arr.Contains(f.id)).ToList().Clone();
                    LoadPermissionValue(m, m.options);
                    LoadOptionSelected(roleId, m, rmoList);
                }
            });
        }

        public void Load(Menu model)
        {
            if (model.IsNull())
                return;

            if (!model.parentId.NotContent())
            {
                var parent = GetEntity(model.parentId);
                if (parent.NotNull())
                    model.parentLabel = parent.label;

                var options = optionService.GetList(queryable => queryable.OrderBy(a => a.sort), false);
                if (!model.optionIds.IsNullOfEmpty() && !options.IsNullOfEmpty())
                {
                    var arr = model.optionIds.SplitStrList();
                    model.options = options.Where(m => arr.Contains(m.id)).ToList().Clone();
                    LoadPermissionValue(model, model.options);
                }
            }

        }

        #endregion

        #region 辅助方法

        /// <summary>
        /// 加载权限值
        /// </summary>
        public void LoadPermissionValue(Menu model, List<Option> options)
        {
            if (options.IsNullOfEmpty())
                return;

            if (model.component.IsNullOrEmpty())
                return;

            options.ForEach(m => m.value = $"{model.component.Replace("views/", "")}/{m.id}");
        }

        /// <summary>
        /// 加载菜单默认选中配置
        /// </summary>
        /// <param name="opt"></param>
        private void LoadOptionSelected(int? roleId, Menu model, List<RoleJoinMenuOption> rmoList)
        {
            if(roleId.NotContent())
                return;
            if(model.options.IsNullOfEmpty())
                return;
            var options = rmoList.Where(f => f.roleId == roleId.Value && f.menuId == model.id);
            if(options.IsNullOfEmpty())
                return;

            model.options.ForEach(opt =>
            {
                opt.selected = options.FirstOrDefault(f => f.optionId == opt.id).NotNull();
            });
        }


        #endregion

    }
}
